package com.yupi.yuojbackendjudgeservice.judge.impl;

import cn.hutool.json.JSONUtil;
import com.yupi.yuojbackendmodel.codesanbox.ExecuteCodeRequest;
import com.yupi.yuojbackendmodel.codesanbox.ExecuteCodeResponse;
import com.yupi.yuojbackendmodel.codesanbox.JudgeInfo;
import com.yupi.yuojbackendmodel.model.dto.question.JudgeCase;
import com.yupi.yuojbackendmodel.model.entity.Question;
import com.yupi.yuojbackendmodel.model.entity.QuestionSubmit;
import com.yupi.yuojbackendmodel.model.enums.JudgeInfoMessageEnum;
import com.yupi.yuojbackendmodel.model.enums.QuestionSubmitStatusEnum;
import com.yupi.yuojbackendcommon.common.ErrorCode;
import com.yupi.yuojbackendcommon.exception.BusinessException;
import com.yupi.yuojbackendjudgeservice.judge.JudgeManager;
import com.yupi.yuojbackendjudgeservice.judge.JudgeService;
import com.yupi.yuojbackendjudgeservice.judge.codesanbox.CodeSanBox;
import com.yupi.yuojbackendjudgeservice.judge.codesanbox.CodeSanBoxFactory;
import com.yupi.yuojbackendjudgeservice.judge.codesanbox.CodeSanBoxProxy;
import com.yupi.yuojbackendjudgeservice.judge.strategy.DefaultStrategy;
import com.yupi.yuojbackendjudgeservice.judge.strategy.JudgeContext;
import com.yupi.yuojbackendjudgeservice.judge.strategy.JudgeStrategy;
import com.yupi.yuojbackendserviceclient.service.QuestionFeignClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author FengHuan Wang
 * @Date 2025/3/9 10:37
 * @Version 1.0
 */
@Service
public class JudgeServiceImpl implements JudgeService {

    @Resource
    private QuestionFeignClient questionFeignClient;


    @Resource
    private JudgeManager judgeManager;

    @Value("${codesanbox.type:example}")
    private String type;

    @Override
    public QuestionSubmit doJudge(long questionSubmitId) {

        // 1、传入题目的提交id 获取到对应的题目、提交信息（包含代码、编程语言等）
        QuestionSubmit questionSubmit = questionFeignClient.getQuestionSubmitById(questionSubmitId);
        if (questionSubmit == null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目信息不存在");
        }
        Long questionId = questionSubmit.getQuestionId();
        Question question = questionFeignClient.getQuestionById(questionId);

        if (question == null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目不存在");
        }

        //如果题目的判题状态不是等待中
        if ( !questionSubmit.getStatus().equals(QuestionSubmitStatusEnum.WAITING.getValue())){
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "题目正在判题中");
        }


        // 2、调用代码沙箱，获取到执行结果
        CodeSanBox codeSanBox = CodeSanBoxFactory.newInstance(type);
        codeSanBox = new CodeSanBoxProxy(codeSanBox);
        String language = questionSubmit.getLanguage();
        String code = questionSubmit.getCode();
        //获取输入用例
        String judgeCase = question.getJudgeCase();
        List<JudgeCase> judgeCaseList = JSONUtil.toList(judgeCase, JudgeCase.class);
        List<String> inputList = judgeCaseList.stream().map(JudgeCase::getInput).collect(Collectors.toList());
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .code(code)
                .language(language)
                .inputList(inputList)
                .build();
        ExecuteCodeResponse executeCodeResponse = null;
        executeCodeResponse = codeSanBox.executeCode(executeCodeRequest);

        //获取代码沙箱的输出结果
        List<String> outputList = executeCodeResponse.getOutputList();
        // 从代码沙箱的执行结果中获取执行耗时
        JudgeContext judgeContext = new JudgeContext();
        // 调用的是远程Docker代码沙箱,直接可以获取到程序的执行内存
        executeCodeResponse.setJudgeInfo(JudgeInfo.builder()
                .memoryLimit(executeCodeResponse.getJudgeInfo().getMemoryLimit())
                .timeLimit(executeCodeResponse.getJudgeInfo().getTimeLimit())
                .build());
        judgeContext.setJudgeInfo(executeCodeResponse.getJudgeInfo());

        judgeContext.setInputList(inputList);
        judgeContext.setOutputList(outputList);
        judgeContext.setCaseList(judgeCaseList);
        judgeContext.setQuestion(question);
        judgeContext.setQuestionSubmit(questionSubmit);
        JudgeStrategy judgeStrategy = new DefaultStrategy();
        JudgeInfo judgeInfo =judgeManager.doJudge(judgeContext);


        //修改数据库中的判题结果
        QuestionSubmit questionSubmitUpdate = new QuestionSubmit();
        questionSubmitUpdate.setId(questionSubmitId);
        questionSubmitUpdate.setStatus(QuestionSubmitStatusEnum.SUCCEED.getValue());
        questionSubmitUpdate.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));
        boolean updateById = questionFeignClient.updateQuestionSubmitById(questionSubmitUpdate);
        if (!updateById){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目更新错误");
        }
        QuestionSubmit byId = questionFeignClient.getQuestionSubmitById(questionId);
        return byId;
    }
}
